package client;

import beans.Draft_Bean;
import beans.Player_Bean;
import beans.User_Bean;
import java.net.*;
import java.util.Vector;
import java.io.*;

/**********************************************************************
*
* Filename: Client_TCP_Connection.java
*
* File Description:
* Class that handles conncction on the client side of the socket
*
* Author:
* @author Tim Schmalz
* Date Created:
*  Oct 9, 2009
*
**********************************************************************/
public class Client_TCP_Connection
{
    private BufferedReader in;
    private PrintStream out;
    private final int MAX_ATTEMPTS = 5;
    ObjectInputStream serialIn;
    ObjectOutputStream serialOut;
    Socket s;
    private final int TIMEOUT_TIME = 100000; //Timeout set to 100 sec

    /**
     * Attempts to open a socket connection with a given hostname and a given
     * port number
     *
     * @param hostname - The name of the host
     * @param port - The port number to connect to
     * @throws Exception - Exception thrown while trying to connect
     */
    public Client_TCP_Connection(String hostname, int port) throws Exception
    {
        s = connectToSocket(hostname, port);
        in = new BufferedReader(new InputStreamReader(s.getInputStream()));
        out = new PrintStream(s.getOutputStream());

        serialOut = new ObjectOutputStream (s.getOutputStream());
        serialIn = new ObjectInputStream (s.getInputStream());
    }

    /**
     * Reads from the Buffered Reader coming from the server
     *
     * @return The incoming message from the server
     * @throws Exception - I/O Exception
     */
    public String readln() throws Exception
    {
        String s;
        try
        {
            s = in.readLine();    
        }
        catch(InterruptedIOException iioe)
        {
            System.err.println("User Timed Out");
            throw new InterruptedIOException();
        }
        catch (IOException ioe)
        {
            System.err.println("TCP input failure: network error");
            throw new Exception("Input Failure: Network I/O Error");
        }
        return s;
    }
    
    /**
     * Reads a serialized message from the coming from the server
     *
     * @return The incoming message from the server
     * @throws Exception - I/O Exception
     */
    public Object serialReadln() throws Exception
    {
        try
        {
        	// Read an object
        	Object obj = serialIn.readObject();
                if (obj instanceof Vector)
        	{
                    // Cast object to a Vector
                    Vector<Player_Bean> players = (Vector) obj;
                    return players;
        	}
        	else if (obj instanceof User_Bean)
        	{
                    return (User_Bean)obj;
        	}
                else if (obj instanceof Draft_Bean)
                {
                    return (Draft_Bean)obj;
                }
        	else
        	{
                    throw new Exception("Unsuported Serialized Class");
        	}
        }
        catch(InterruptedIOException iioe)
        {
            System.err.println("User Timed Out");
            throw new InterruptedIOException();
        }
        catch (IOException ioe)
        {
            System.err.println("TCP input failure: network error");
            throw new Exception("Input Failure: Network I/O Error");
        }
        catch (Exception e)
        {
        	System.err.println(e.getMessage());
        	throw e;
        }
    }

    /**
     * Sends a string to the server
     *
     * @param outString - String to be sent
     */
    public void println(String outString)
    {
        out.println(outString);
        out.flush();
    }
    
    /**
     * Sends a serialized object the server
     *
     * @param out - object to be sent
     * @throws IOException 
     */
    public void serialOut(Object outObject) throws IOException
    {
            //Sends Object
            serialOut.writeObject(outObject);
            serialOut.flush();
    }

    /**
     * Does the connection for the constructor
     *
     * @param hostname - The name of the host
     * @param port - The port number to connect to
     * @return - Returns a connected Socket
     * @throws Exception - Exception thrown while trying to connect
     */
    private Socket connectToSocket(String hostname, int port) throws Exception
    {
        Socket s = null;
        int attempts = 0;
        while(s==null && attempts < MAX_ATTEMPTS)
        {
            try
            {
                s = new Socket(hostname, port);
            }
            catch(UnknownHostException uhe)
            {
                System.err.println("Cannot make TCP connection\n" +
                        "Unknown Host: " + hostname);
                throw new Exception("Connection failed: Host Unknown");
            }
            catch(IOException ioe)
            {
                System.err.println("Connection fail due to Network\n" +
                        "Retrying... " + attempts);
            }
            attempts++;
        }
        if(s==null)
        {
            throw new IOException("Connection Failure: Net I/O Errors");
        }
        //Set Timeout for socket
        try
	{
		s.setSoTimeout(TIMEOUT_TIME);
	}
	catch (SocketException se)
	{
		System.err.println ("Unable to set socket option SO_TIMEOUT");
	}
        return s;
    }

    /**
     * Closes TCP connection
     */
    public void close()
    {
        try
        {
            serialIn.close();
            serialOut.close();
            in.close();
            out.close();
            s.close();
        }
        catch (Exception ex)
        {
            System.err.println("Error closing connection");
        }
    }
}